namespace Gamov.DeleteSdData.Main
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Threading.Tasks;
    using Gamov.DeleteSdData.Main.Frame.Attributes;
    using Gamov.DeleteSdData.Main.Frame.Helper;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using NLog.Extensions.Logging;


    internal class Program
    {
        static async Task Main(string[] args)
        {
            var builder = new HostBuilder().ConfigureAppConfiguration((a) => {
                a.AddConfiguration(new ConfigurationBuilder()
                    .SetBasePath(AppContext.BaseDirectory)
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .Build());
            }).ConfigureServices((hostContext, services) =>
            {
                // 配置服务
                var types = Assembly.GetExecutingAssembly().GetTypes();
                var descriptors = new List<ServiceDescriptor>();
                var hostServiceTypes = new List<Type>();
                var optionTypes = new List<(Type, string)>();

                foreach (var type in types)
                {
                    var attr = type.GetCustomAttribute<ComponentAttribute>();
                    if (attr != null)
                    {
                        descriptors.Add(new ServiceDescriptor(attr.InterfaceType, type, attr.LifeTime));
                    }

                    var attr1 = type.GetCustomAttribute<HostServiceAttribute>();
                    if (attr1 != null)
                    {
                        hostServiceTypes.Add(type);
                    }

                    var attr2 = type.GetCustomAttribute<OptionAttribute>();
                    if (attr2 != null)
                    {
                        optionTypes.Add((type, attr2.RootName));
                    }
                }

                foreach (var item in descriptors)
                {
                    // 依赖注入
                    services.Add(item);
                }

                foreach (var optionType in optionTypes)
                {
                    // 反射绑定配置文件，等价于services.AddOptions<ServerConfig>().Bind(hostContext.Configuration.GetSection("Server"));
                    var result = ReflectsHelper.OptionsServiceCollectionExtensions_AddOptions(optionType.Item1)
                        .Invoke(services, new object[] { services });
                    ReflectsHelper.OptionsBuilderConfigurationExtensions_Bind(optionType.Item1)
                        .Invoke(result, new object[] { result, hostContext.Configuration.GetSection(optionType.Item2) });
                }

                foreach (var hostServiceType in hostServiceTypes)
                {
                    // 反射获取hostservice, 等价于 services.AddHostedService<WebsocketServerHost>();
                    ReflectsHelper.ServiceCollectionHostedServiceExtensions_AddHostedService(hostServiceType).Invoke(services, new object[] { services });
                }

                services.AddLogging(builder1 =>
                {
                    builder1.ClearProviders();
                    builder1.SetMinimumLevel(LogLevel.Information);
                    builder1.AddNLog(hostContext.Configuration);
                });
            }).UseConsoleLifetime();

            await builder.Build().RunAsync();
        }
    }
}
